using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.ServiceModel;
using System.Drawing.Imaging;
using System.ServiceModel.Channels;
using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel.PeerResolvers;
using WMessage = System.Windows.Forms.Message;

namespace PictureViewer
{
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    public partial class frmPictureViewer : Form, IPictureViewer 
    {
        String fileName;

        ServiceHost host;

        ChannelFactory<IPictureViewerClient> channelFactory;
        IPictureViewer channel;

        public frmPictureViewer()
        {
            InitializeComponent();
            StartReceiving();
        }

        private void StartReceiving()
        {
            try
            {
                Uri meshAddress = new Uri("net.p2p://pictureView");
                NetPeerTcpBinding binding = new NetPeerTcpBinding();
                binding.Resolver.Mode = PeerResolverMode.Pnrp;
                //desable the security to simplify the problem.
                //binding.Security.Transport.CredentialType = PeerTransportCredentialType.Password;
                binding.Security.Mode = SecurityMode.None;

                binding.MaxReceivedMessageSize = 700000L;
                host = new ServiceHost(this);

                host.AddServiceEndpoint(typeof(IPictureViewer), binding, meshAddress);
                host.Open();

                channelFactory = new ChannelFactory<IPictureViewerClient>(binding, new EndpointAddress(meshAddress));
                channel = channelFactory.CreateChannel();
            }
            catch (Exception ec)
            {
                System.Diagnostics.Debug.WriteLine("ERROR: " + ec.Message);
                //Console.WriteLine("Error: {0}", ec.Message);
            }
        }

        private void btnBrowse_Click(object sender, EventArgs e)
        {
            Stream stream;

            if (ofdPicture.ShowDialog() == DialogResult.OK)
            {
                txtFileName.Text = ofdPicture.FileName;
                if ((stream = ofdPicture.OpenFile()) != null)
                {
                    SharePicture(stream);
                    fileName = ParseFileName(txtFileName.Text);
                    lblFileName.Text = fileName;
                }
            }
        }

        private string ParseFileName(String fullPath)
        {
            String[] strings = fullPath.Split('\\');
            return strings[strings.Length-1];
        }

        public void SharePicture(Stream stream)
        {
            Image image = Bitmap.FromStream(stream);
            pbView.SizeMode = PictureBoxSizeMode.StretchImage;
            pbView.Image = image;
        }

        public void SharePath(FileNameMessage fileName)
        {
            lblFileName.Text = fileName.Value;
        }


        private void btnShare_Click(object sender, EventArgs e)
        {
            MemoryStream stream = new MemoryStream();
            Image image = pbView.Image;
         
            image.Save(stream, ImageFormat.Jpeg);
            stream.Position = 0;

            channel.SharePicture(stream);

            Int32 hopCount = Convert.ToInt32(txtHopCount.Text);
            FileNameMessage fnm = new FileNameMessage(hopCount, fileName);
            
            channel.SharePath(fnm);

        }

        #region title interop

        protected void OnNonClientPaint(PaintEventArgs args)
        {
            Point pt = new Point(
               Size.Width - SystemInformation.CaptionButtonSize.Width * 3,
               SystemInformation.CaptionHeight);

            StringFormat fmt = new StringFormat();

            fmt.Alignment = StringAlignment.Far;
            fmt.LineAlignment = StringAlignment.Far;

            args.Graphics.DrawString("The Best Way To Share A Photo", new Font("Franklin Gothic Medium", 13),
               Brushes.White, pt, fmt);
        }

        protected override void WndProc(ref WMessage message)
        {
            const Int32 WM_NCPAINT = 0x0085;
            const Int32 WM_NCACTIVATE = 0x0086;
            switch (message.Msg)
            {

                case WM_NCACTIVATE:
                case WM_NCPAINT:
                    base.WndProc(ref message);

                    IntPtr hdc = Win32.GetWindowDC(message.HWnd);
                    if (hdc != IntPtr.Zero)
                    {
                        using (Graphics graphics = Graphics.FromHdc(hdc))
                        {
                            Rectangle rect = new Rectangle(0, 0, Size.Width, Size.Height);
                            PaintEventArgs args = new PaintEventArgs(graphics, rect);
                            OnNonClientPaint(args);
                        }
                        Win32.ReleaseDC(message.HWnd, hdc);
                    } // weak failure case here     

                    break;

                default:
                    // Pass all others to base
                    base.WndProc(ref message);
                    break;
            }
        }

        class Win32
        {
            [DllImport("User32.dll", SetLastError = true)]
            internal static extern IntPtr GetWindowDC(IntPtr hwnd);

            [DllImport("User32.dll", SetLastError = true)]
            internal static extern Int32 ReleaseDC(
               IntPtr hWnd, IntPtr hdc);
        }
        #endregion

        interface IPictureViewerClient : IPictureViewer, IClientChannel { }

        private X509Certificate2 GetCertificate()
        {
            X509Store store = new X509Store(StoreLocation.CurrentUser);
            store.Open(OpenFlags.ReadOnly);
            X509Certificate2Collection matches;

            matches = store.Certificates.Find(X509FindType.FindBySubjectName, "PictureView", false);
            return matches[0];
        }
    }

    [ServiceContract]
    interface IPictureViewer
    {
        [OperationContract(IsOneWay = true)]
        void SharePicture(Stream stream);

        [OperationContract(IsOneWay = true)]
        void SharePath(FileNameMessage path);
    }

    [MessageContract]
    public class FileNameMessage
    {
        [PeerHopCount] Int32 hopCount;
        [MessageBodyMember] String value;

        public String Value
        {
            get { return value; }
        }

        public FileNameMessage() { }
        public FileNameMessage(Int32 hopCount, String fileName)
        {
            this.hopCount = hopCount;
            this.value = fileName;
        }
    }
}